import config from "@/common/app/config.js";
const publicKey =
  "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuPYqmaJGniQ5bBHmZM27ln1YEBgJQNWyzyye92uz2V7QDrc4itkqUitw9uncs5TNPlSo9wvr0cO2589gmezbE97ZL/D9esYo8LGRJ0NGyuBPxSxB78miXkxWKhFvI1LbaV42brLcwZhb1vAKCZ4z/8FEz/3dukHIb9DucJk8lpX2RWaqpnV1vg7Ng7/Wi5522bss8v8wjKDIxfW2Qo+TE8hUu9Adu7ZZL1MXoZwm8p/DQBU7NvQvc6aD3QS7MxW/7pUd7j2YASNbFuAdVTCmRoZMExE+eKqPP+LpUlcRdol0boDbVf47SVHNcvyDX32B19p+PCPNetkJsTYCV80cFwIDAQAB";

export default {
  /**
   * 使用与后台约定好的加密方式加密用户密码
   * 前端涉及到密码的都需要加密处理，使用的是RSA,PKCS8加密方式，秘钥为：publicKey
   * @param {String} password 需加密的明文密码
   * @returns 加密后的密文密码
   */
  encrypt(password) {
    const encrypt = new window.JSEncrypt();
    encrypt.setPublicKey(publicKey);
    const encryptedPassword = encrypt.encrypt(password);
    return encryptedPassword;
  },
  /**
   * 根据图片文件code获取图片文件流
   * @param {Object} fileCode 图片文件code
   */
  getImageUrlByFileCode(fileCode) {
    if (!fileCode || !fileCode.length) {
      return config.DEFAULT_PICTURE;
    }
    return this.getApiUrl(
      "/common/file/downLoadFileStream.json?fileCode=" + fileCode
    );
  },
  /**
   * 根据文件名称下载文件到本地（直接访问文件存放路径以下载文件）
   * @param {Object} fileName 文件名
   */
  downloadFileByFileName(fileName) {
    if (!fileName || !fileName.length) {
      return;
    }
    const fileUrl = this.getApiUrl("/downloads/" + fileName);
    window.open(fileUrl);
  },

  /**
   * 清除用户信息并退出登录页面
   */
  redirectToLogin() {
    // TODO 用户退出登录前，先清除所有用户信息
  },

  /**
   * 设置底部导航栏的未读消息角标
   */
  setUnreadCount() {
    // TODO 设置未读消息数
  },
  /**
   * 根据值从树状结构对象中获取包含该值的所有数据
   * @param {Object} tree 树状结构的数据对象
   * @param {String} value 需要查找的值
   * @param {String} key 查找值对应的字段名称
   * @param {String} childrenNode 树状结构的子节点名称
   * @returns
   */
  filterTreeByRole(tree, value, key = "roles", childrenNode = "children") {
    // 深拷贝树以避免修改原数据
    const treeCopy = JSON.parse(JSON.stringify(tree));

    // 辅助函数：检查节点或其子节点是否包含目标 role
    function hasRole(node) {
      if (node[key] && node[key].includes(value)) {
        return true;
      }

      if (node[childrenNode] && node[childrenNode].length > 0) {
        return node[childrenNode].some((child) => hasRole(child));
      }

      return false;
    }

    // 辅助函数：筛选树
    function filterNodes(nodes) {
      return nodes
        .filter((node) => hasRole(node))
        .map((node) => {
          const newNode = { ...node };

          if (newNode[childrenNode] && newNode[childrenNode].length > 0) {
            newNode[childrenNode] = filterNodes(newNode[childrenNode]);
          }

          return newNode;
        });
    }

    return filterNodes(treeCopy);
  },
  /**
   * 根据指定值从树状结构的对象中获取包含该值的节点及所有父节点
   * @param {*} tree 树状结构的数据对象
   * @param {*} value 需要匹配的值
   * @param {*} key 匹配值对应的字段名称
   * @param {*} childrenNode 树状结构的子节点名称
   * @returns
   */
  findBreadcrumbByPath(tree, value, key = "path", childrenNode = "children") {
    const stack = [];

    // 初始化栈，包含树的所有顶层节点和空路径
    for (const node of tree) {
      stack.push({ node, path: [] });
    }

    while (stack.length > 0) {
      const { node, path } = stack.pop();

      if (node[key] === value) {
        return [...path, node];
      }

      if (node[childrenNode] && node[childrenNode].length > 0) {
        // 将子节点按顺序推入栈（注意顺序，因为栈是后进先出）
        for (let i = node[childrenNode].length - 1; i >= 0; i--) {
          stack.push({ node: node[childrenNode][i], path: [...path, node] });
        }
      }
    }

    return null;
  },

  /**
   * 根据指定字段从树状结构的对象中获取第一个不为空的节点
   * @param {*} tree 树状结构的数据对象
   * @param {*} key 匹配值对应的字段名称
   * @param {*} childrenNode 树状结构的子节点名称
   * @returns
   */
  findFirstNode(tree, key = "path", childrenNode = "children") {
    // 使用广度优先搜索 (BFS) 实现
    const queue = [...tree];

    while (queue.length > 0) {
      const node = queue.shift();

      // 检查当前节点的 path 是否存在且不为空
      if (node[key]) {
        return node;
      }

      // 将子节点加入队列
      if (node[childrenNode] && node[childrenNode].length > 0) {
        queue.push(...node[childrenNode]);
      }
    }

    return null; // 没有找到符合条件的节点
  },
  /**
   * 将树状结构转换为扁平数组，并设置父节点ID
   * @param {Array} tree 树状结构数据
   * @param {string} nodeId 需要取的父节点字段名称
   * @param {string} [childrenKey='children'] 子节点属性名，默认为'children'
   * @returns {Array} 返回扁平化后的数组
   */ flattenTreeWithParentId(
    tree,
    nodeId = "index",
    childrenKey = "children"
  ) {
    const result = [];

    // 递归遍历函数
    function traverse(node, parentId) {
      // 创建当前节点对象，设置parent为父节点ID
      const currentNode = {
        ...node,
        parent: node.parent || parentId || null, // 如果没有父节点则设为null
      };

      // 添加到结果数组
      result.push(currentNode);

      // 处理子节点
      if (node[childrenKey] && node[childrenKey].length > 0) {
        // 先删除children属性，避免在结果中保留
        delete currentNode[childrenKey];

        // 遍历子节点，传入当前节点ID作为父ID
        node[childrenKey].forEach((child) => {
          traverse(child, node[nodeId]);
        });
      }
    }

    // 从根节点开始遍历
    tree.forEach((rootNode) => {
      traverse(rootNode, null); // 根节点的parent为null
    });

    return result;
  },
  /**
   * 根据节点ID查找节点及其所有父节点（从根到叶子排序）
   * @param {Array} flatArray 扁平化的节点数组
   * @param {string} nodeValue 要查找的节点值
   * @param {string} nodeKey 要查找的节点值对应的字段名称
   * @param {string} [idKey='id'] ID属性名，默认为'id'
   * @returns {Array|null} 返回从根节点到目标节点的数组，如果未找到则返回null
   */
  findNodeWithAncestorsOptimized(
    flatArray,
    nodeValue,
    nodeKey = "path",
    idKey = "index"
  ) {
    // 构建ID到节点的映射表
    const nodeMap = {};
    // 设置目标节点
    let targetNode = null;
    flatArray.forEach((node) => {
      nodeMap[node[idKey]] = node;
      if (node[nodeKey] === nodeValue) {
        targetNode = node;
      }
    });

    if (!targetNode) return null;

    // 收集所有祖先节点
    const result = [targetNode];
    let currentParentId = targetNode.parent;

    while (currentParentId !== null) {
      const parentNode = nodeMap[currentParentId];
      if (!parentNode) break;

      result.unshift(parentNode);
      currentParentId = parentNode.parent;
    }

    return result;
  },
  /**
   * 将文件流下载为指定的文件名
   * @param {String} fileName
   * @param {Blob} fileStream
   */
  downloadBlobFile(fileName = "", fileStream = {}) {
    const fileType = fileName.split(".")[fileName.split(".").length - 1].toLocaleLowerCase();
    // new Blob的第二个参数可以按如下设置：
    // word文件：
    // .doc格式的设置为：application/vnd.msword;charset=utf-8
    // .docx格式的设置为：application/vnd.openxmlformats-officedocument.wordprocessingml.document
    // excel文件：
    // .xls格式的设置为：application/vnd.ms-excel
    // .xlsx格式的设置为：application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
    // zip文件：
    // . zip格式的设置为：application/zip
    const blobType = {
      doc: "application/vnd.msword;charset=utf-8",
      docx: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
      xls: "application/vnd.ms-excel",
      xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
      zip: "application/zip",
    };

    let url = (window.URL || window.webkitURL).createObjectURL(
      new Blob([fileStream], {
        type: blobType[fileType],
      })
    );
    let link = document.createElement("a");
    link.style.display = "none";
    link.href = url;
    link.setAttribute("download", fileName);
    document.body.appendChild(link);
    link.click();
    document.body.removeChild(link);
  },
};
